package net.cyan.activex;

import java.lang.reflect.*;
import java.util.Date;

import java.awt.Color;

import com.jacob.com.*;
import net.sf.cglib.core.CodeGenerationException;
import net.sf.cglib.proxy.*;

/**
 * <p>Title: activex对象接口</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2006</p>
 * <p>Company: </p>
 * @author ccs
 * @version 1.0
 */
public class ActiveXProxy implements MethodInterceptor
{
   private Dispatch dispatch;

   private Class c;

   private ActiveXProxy(Dispatch dispatch, Class c)
   {
      this.dispatch = dispatch;
      this.c = c;
   }

   public Object intercept(Object object, Method method, Object[] objectArray,
                           MethodProxy methodProxy) throws Throwable
   {
      String methodName = method.getName();
      if ("getDispatch".equals(methodName))
         return dispatch;

      if (Modifier.isAbstract(method.getModifiers()))
      {
         Variant v = null;

         Class type = method.getReturnType();
         if (methodName.startsWith("set") && objectArray.length == 1 && type == void.class)
         {
            String property = methodName.substring(3);
            try
            {
               Object obj = objectArray[0];
               if (obj instanceof ActiveXObject)
                  obj = ( (ActiveXObject) obj).getDispatch();
               else if (obj instanceof Color)
                  obj = new Integer(colorToRgb( (Color) obj));
               Dispatch.put(dispatch, property, obj);

               return null;
            }
            catch (Throwable ex)
            {
               throw new ActiveXException(c.getName() + "设置activex属性" +
                                          property + "错误", ex);
            }
         }
         else if ( (methodName.startsWith("get") || methodName.startsWith("is")) &&
                  objectArray.length == 0)
         {
            String property = null;
            if (methodName.startsWith("is"))
               property = methodName.substring(2);
            else
               property = methodName.substring(3);

            try
            {
               v = Dispatch.get(dispatch, property);
            }
            catch (Throwable ex)
            {
               throw new ActiveXException(c.getName() + "获取activex属性" +
                                          property + "错误", ex);
            }
         }
         else
         {
            methodName = Character.toUpperCase(methodName.charAt(0)) +
                methodName.substring(1);
            try
            {
               for (int i = 0; i < objectArray.length; i++)
               {
                  if (objectArray[i] instanceof ActiveXObject)
                     objectArray[i] = ( (ActiveXObject) objectArray[i]).
                         getDispatch();
                  else if (objectArray[i] instanceof Color)
                     objectArray[i] = new Integer(colorToRgb( (Color)
                         objectArray[i]));
               }

               v = Dispatch.callN(dispatch, methodName, objectArray);
            }
            catch (Throwable ex)
            {
               throw new ActiveXException(c.getName() + "调用activex方法" +
                                          methodName + "错误", ex);
            }
         }

         return getResult(v, type);
      }
      else
      {
         return methodProxy.invokeSuper(object, objectArray);
      }
   }

   public static ActiveXObject createObject(Class c, Dispatch dispacth) throws
       ActiveXException
   {
      try
      {
         ActiveXProxy proxy = new ActiveXProxy(dispacth, c);
         return (ActiveXObject) Enhancer.create(c, proxy);
      }
      catch (CodeGenerationException ex)
      {
         Throwable cause = ex.getCause();
         if (cause instanceof RuntimeException)
         {
            throw (RuntimeException) cause;
         }
         else
         {
            throw new ActiveXException("创建ActiveX对象" + c.getName() + "失败:",
                                       cause);
         }
      }
   }

   private Object getResult(Variant v, Class type) throws ActiveXException
   {
      if (type == void.class)
         return null;
      else if (type == boolean.class || type == Boolean.class)
         return v.getBoolean() ? Boolean.TRUE : Boolean.FALSE;
          else if (type == byte.class || type == Byte.class)
         return new Byte(v.getByte());
      else if (type == int.class || type == Integer.class)
         return new Integer(v.getInt());
      else if (type == short.class || type == Short.class)
         return new Short(v.getShort());
      else if (type == long.class || type == Long.class)
         return new Long(v.getCurrency());
      else if (type == float.class || type == Float.class)
         return new Float(v.getFloat());
      else if (type == double.class || type == Double.class)
         return new Double(v.getDouble());
      else if (type == char.class || type == Character.class)
         return new Character(v.getString().charAt(0));
      else if (type == String.class)
         return v.getString();
      else if (type == Date.class)
         return new Date( (long) v.getDate());
      else if (ActiveXObject.class.isAssignableFrom(type))
         return createObject(type, (Dispatch) v.getDispatch());
      else if (type == Variant.class)
         return v;
      else if (type == Dispatch.class)
         return v.getDispatch();
      else if (type == Color.class)
         return rgbToColor(v.getInt());

      if (type.isArray())
      {
         Variant[] array = v.getVariantArray();
         type = type.getComponentType();
         Object result = Array.newInstance(type, array.length);
         for (int i = 0; i < array.length; i++)
         {
            Array.set(result, i, getResult(array[i], type));
         }
      }

      throw new ActiveXException(" 不支持的activeX结果类型" + type.getName());
   }

   public int colorToRgb(Color color)
   {
      return color.getRed() + color.getGreen() * 256 +
          color.getBlue() * 256 * 256;
   }

   public Color rgbToColor(int rgb)
   {
      if (rgb < 0)
         return null;
      int r = rgb % 256;
      rgb = rgb / 256;
      int g = rgb % 256;
      int b = rgb / 256;

      return new Color(r, g, b);
   }
}
